#ifndef DBFILE_H
#define DBFILE_H

#include "TwoWayList.h"
#include "Record.h"
#include "Schema.h"
#include "File.h"
#include "Comparison.h"
#include "ComparisonEngine.h"
#include "BigQ.h"

struct SortInfo {
	OrderMaker* myOrder;
	int runLength;
};

typedef enum {
	heap, sorted, tree
} fType;

// Do NOT introduce pointer in the structure - metaData. If you have to, then change
// the function FileMetaData::WriteMetaData.
typedef struct metaData {
	fType myType;
	OrderMaker om;
	int runLength;
};

class FileMetadata {
private:
	void GenerateMetadataName(char* f_path, char** f_metadata);
public:
	metaData mydata;
	FileMetadata();
	int LoadMetaData(char* f_path);
	int WriteMetaData(char* f_path);
};

class GenericDBFile {
private:
public:
	GenericDBFile() {
	}
	virtual int Close() = 0;
	virtual void Load(Schema &myschema, char *loadpath) = 0;
	virtual void MoveFirst() = 0;
	virtual void Add(Record &addme) = 0;
	virtual int GetNext(Record &fetchme) = 0;
	virtual int GetNext(Record &fetchme, CNF &cnf, Record &literal) = 0;
};

class Heap: public GenericDBFile {
private:
	Page *myPage;
	File *myFile;
	Record *currentRecord;
	off_t currentPage; //Page number starts from 0
	off_t lastReadPage;
	long lastReadRecord; //Record number starts from 1
	FileMetadata *myMetadata;
	bool isDirty;
	bool isAddDone;
	int writeDirtyPage();
	void Initialize();
public:
	Heap();
	~Heap();
	Heap(char *fpath, int open, FileMetadata *meta);
	virtual int Close();
	virtual void Load(Schema &myschema, char *loadpath);
	virtual void MoveFirst();
	virtual void Add(Record &addme);
	virtual int GetNext(Record &fetchme);
	virtual int GetNext(Record &fetchme, CNF &cnf, Record &literal);
};

typedef enum {
	reading, writing
} mode;

class Sorted: public GenericDBFile {
private:
	Page *myPage;
	File *myFile;
	BigQ *myQueue;
	Pipe *inPipe;
	Pipe *outPipe;
	mode myMode;
	Record *currentRecord;
	ComparisonEngine ceng;
	char *filePath;
	off_t currentPage; //Page number starts from 0
	FileMetadata *myMetadata;
	OrderMaker queryOrderMaker;
	OrderMaker literalOrderMaker;
	bool queryOrderMakerSet;
	bool matchingPage;
	bool pageAdded;
	Page *oldPage;
	int oldPageNum;
	int set;
	void Initialize();
	void setMode(mode);
	void writeIntoFile();
	void AddToPage(Record*, Page*, File*, off_t*);
	int BinarySearch(int low, int high, Record &literal);

	int GetMatchPage(Record &literal);
	void RestorePage();
	void SavePage();

public:
	Sorted();
	Sorted(char *fpath, int open, FileMetadata *meta);
	virtual void Add(Record &addme);
	virtual void Load(Schema &myschema, char *loadpath);
	virtual void MoveFirst();
	virtual int GetNext(Record &fetchme);
	virtual int GetNext(Record &fetchme, CNF &cnf, Record &literal);
	virtual int Close();

};

class DBFile {
private:
	GenericDBFile* genDB;
	FileMetadata myMetadata;
public:
	DBFile();
	~DBFile();
	int Create(char *fpath, fType file_type, void *startup);
	int Open(char *fpath);
	int Close();
	void Load(Schema &myschema, char *loadpath);
	void MoveFirst();
	void Add(Record &addme);
	int GetNext(Record &fetchme);
	int GetNext(Record &fetchme, CNF &cnf, Record &literal);

};

#endif
